/**
 * WorthDoing.ai
 * Author: Simon-Pierre Boucher
 * Contact: contact@spboucher.ai
 * File: src/app/investigate/[id]/InvestigationLive.tsx
 * Description: Live investigation client view — SSE timeline, animating hypotheses, opportunities, streamed reports; mobile tabs.
 */
"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import Link from "next/link";
import { cn } from "@/lib/utils";
import {
  useInvestigationEvents,
  useSnapshot,
  type UiAgentEvent,
} from "@/lib/ui/api";
import { Timeline } from "@/components/wd/Timeline";
import { HypothesisPanel } from "@/components/wd/HypothesisPanel";
import { StatsBar } from "@/components/wd/StatsBar";
import { PhaseBadge, InvestigationStatusBadge } from "@/components/wd/badges";
import { WorthScore } from "@/components/wd/OpportunityCard";
import { Markdown } from "@/components/wd/Markdown";

const STRUCTURAL_EVENTS = new Set([
  "investigation.started",
  "phase.changed",
  "budget.updated",
  "hypothesis.created",
  "hypothesis.updated",
  "hypothesis.rejected",
  "evidence.saved",
  "opportunity.created",
  "report.completed",
  "investigation.completed",
  "investigation.failed",
]);

type MobileTab = "timeline" | "hypotheses" | "opportunities";

export function InvestigationLive({ id }: { id: string }) {
  const { snapshot, refresh, error } = useSnapshot(id);
  const [events, setEvents] = useState<UiAgentEvent[]>([]);
  const [reportDraft, setReportDraft] = useState<{ opportunityId: string; text: string } | null>(null);
  const [tab, setTab] = useState<MobileTab>("timeline");
  const feedRef = useRef<HTMLDivElement>(null);
  const refreshTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  const onEvent = useCallback(
    (e: UiAgentEvent) => {
      if (e.type === "report.delta") {
        const oid = String(e.payload.opportunityId);
        setReportDraft((prev) =>
          prev && prev.opportunityId === oid
            ? { opportunityId: oid, text: prev.text + String(e.payload.delta) }
            : { opportunityId: oid, text: String(e.payload.delta) },
        );
        return;
      }
      if (e.type === "report.started") setReportDraft({ opportunityId: String(e.payload.opportunityId), text: "" });
      if (e.type === "report.completed") setReportDraft(null);

      setEvents((prev) => {
        if (prev.some((p) => p.seq === e.seq)) return prev;
        const next = [...prev, e].sort((a, b) => a.seq - b.seq);
        return next.length > 400 ? next.slice(next.length - 400) : next;
      });

      if (STRUCTURAL_EVENTS.has(e.type)) {
        // Debounce snapshot refreshes so bursts don't stampede the API.
        if (refreshTimer.current) clearTimeout(refreshTimer.current);
        refreshTimer.current = setTimeout(refresh, 400);
      }
    },
    [refresh],
  );

  const { connected } = useInvestigationEvents(id, onEvent);

  // Keep the feed pinned to the latest event.
  useEffect(() => {
    const el = feedRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [events.length, reportDraft?.text.length]);

  if (error) {
    return (
      <div className="mx-auto max-w-2xl px-4 py-24 text-center">
        <p className="font-heading text-2xl text-ink">Investigation not found</p>
        <p className="mt-2 text-sm text-ink-soft">{error}</p>
        <Link href="/" className="mt-6 inline-block rounded-md bg-ink px-4 py-2 text-sm text-paper">
          Start a new one
        </Link>
      </div>
    );
  }
  if (!snapshot) {
    return (
      <div className="flex items-center justify-center py-32">
        <span className="wd-live-dot h-2.5 w-2.5 rounded-full bg-verdict" />
      </div>
    );
  }

  const inv = snapshot.investigation;
  const isLive = inv.status === "running" || inv.status === "pending";

  const rightColumn = (
    <>
      <section className="rounded-xl border border-line bg-card p-4">
        <h2 className="mb-3 flex items-center justify-between font-mono text-[11px] uppercase tracking-widest text-ink-soft">
          Hypotheses
          <span className="text-ink">{snapshot.hypotheses.length}</span>
        </h2>
        <HypothesisPanel hypotheses={snapshot.hypotheses} />
      </section>

      <section className="rounded-xl border border-line bg-card p-4">
        <h2 className="mb-3 flex items-center justify-between font-mono text-[11px] uppercase tracking-widest text-ink-soft">
          Opportunities
          <span className="text-ink">{snapshot.opportunities.length}</span>
        </h2>
        {snapshot.opportunities.length === 0 ? (
          <p className="py-4 text-center font-mono text-xs text-ink-soft">
            none yet — opportunities appear when hypotheses survive the skeptic
          </p>
        ) : (
          <ul className="space-y-3">
            {snapshot.opportunities.map((o) => (
              <li key={o.id} className="wd-enter">
                <Link
                  href={o.hasReport ? `/opportunity/${o.id}` : "#"}
                  className={cn(
                    "flex items-start justify-between gap-3 rounded-lg border border-line p-3 transition-colors",
                    o.hasReport ? "hover:border-verdict/40 hover:bg-accent/50" : "cursor-default opacity-80",
                  )}
                >
                  <div className="min-w-0">
                    <p className="text-[13px] font-medium leading-snug text-ink">{o.title}</p>
                    <p className="mt-1 line-clamp-2 text-xs text-ink-soft">{o.summary}</p>
                    {!o.hasReport && (
                      <p className="mt-1 font-mono text-[10px] uppercase tracking-wider text-signal">
                        report in progress…
                      </p>
                    )}
                  </div>
                  <WorthScore score={o.worthScore} confidence={o.evidenceConfidence} />
                </Link>
              </li>
            ))}
          </ul>
        )}
      </section>

      {snapshot.sources.length > 0 && (
        <section className="rounded-xl border border-line bg-card p-4">
          <h2 className="mb-3 flex items-center justify-between font-mono text-[11px] uppercase tracking-widest text-ink-soft">
            Sources with evidence
            <span className="text-ink">{snapshot.sources.length}</span>
          </h2>
          <ul className="space-y-1.5">
            {snapshot.sources.map((s) => (
              <li key={s.id} className="truncate">
                <a
                  href={s.canonicalUrl}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="font-mono text-[11px] text-tele hover:underline"
                >
                  {s.title ?? s.canonicalUrl}
                </a>
              </li>
            ))}
          </ul>
        </section>
      )}
    </>
  );

  const timelinePane = (
    <section className="flex min-h-0 flex-col rounded-xl border border-line bg-card">
      <div className="flex items-center justify-between border-b border-line px-4 py-2.5">
        <h2 className="font-mono text-[11px] uppercase tracking-widest text-ink-soft">Investigation log</h2>
        <span
          className={cn(
            "flex items-center gap-1.5 font-mono text-[10px] uppercase tracking-wider",
            connected ? "text-verdict" : "text-signal",
          )}
        >
          <span className={cn("h-1.5 w-1.5 rounded-full bg-current", connected && isLive && "wd-live-dot")} />
          {connected ? (isLive ? "live" : "replay") : "reconnecting"}
        </span>
      </div>
      <div ref={feedRef} className="min-h-[300px] flex-1 overflow-y-auto p-4 lg:max-h-[calc(100vh-260px)]">
        <Timeline events={events} />
        {reportDraft && (
          <div className="wd-enter mt-4 rounded-lg border border-verdict/30 bg-accent/40 p-4">
            <p className="mb-2 font-mono text-[10px] uppercase tracking-widest text-verdict">
              writing report — streaming
            </p>
            <p className="whitespace-pre-wrap text-[13px] leading-relaxed text-ink/90">
              {reportDraft.text}
              <span className="wd-live-dot ml-0.5 inline-block h-3.5 w-[2px] translate-y-0.5 bg-verdict" />
            </p>
          </div>
        )}
      </div>
    </section>
  );

  return (
    <div className="mx-auto w-full max-w-6xl px-4 py-6 sm:px-6">
      <div className="mb-4 flex flex-wrap items-center gap-2">
        <InvestigationStatusBadge status={inv.status} live />
        <PhaseBadge phase={inv.phase} live={isLive} />
        <span className="ml-auto font-mono text-[10px] uppercase tracking-wider text-ink-soft">{inv.model}</span>
      </div>
      <h1 className="mb-4 max-w-4xl font-heading text-2xl font-semibold leading-tight text-ink sm:text-3xl">
        {inv.objective}
      </h1>

      {inv.status === "completed" && inv.conclusion && (
        <div className="wd-enter mb-4 rounded-xl border border-verdict/30 bg-accent/50 p-4">
          <p className="font-mono text-[10px] uppercase tracking-widest text-verdict">
            conclusion — {inv.outcome?.replaceAll("_", " ")}
          </p>
          <div className="mt-2">
            <Markdown>{inv.conclusion}</Markdown>
          </div>
        </div>
      )}
      {inv.status === "failed" && (
        <div className="mb-4 rounded-xl border border-rust/30 bg-rust/5 p-4">
          <p className="font-mono text-[10px] uppercase tracking-widest text-rust">investigation failed</p>
          <p className="mt-2 text-sm text-ink">{inv.error ?? "Unknown error."}</p>
        </div>
      )}

      <div className="sticky top-14 z-30 -mx-1 bg-paper/95 px-1 py-2 backdrop-blur-sm">
        <StatsBar
          budget={inv.budget}
          used={inv.budgetUsed}
          evidenceCount={snapshot.evidenceCount}
          hypothesisCount={snapshot.hypotheses.length}
        />
      </div>

      {/* Mobile tabs */}
      <div className="mt-3 flex gap-1 rounded-lg border border-line bg-card p-1 lg:hidden">
        {(
          [
            ["timeline", "Timeline"],
            ["hypotheses", "Hypotheses"],
            ["opportunities", "Results"],
          ] as [MobileTab, string][]
        ).map(([key, label]) => (
          <button
            key={key}
            onClick={() => setTab(key)}
            className={cn(
              "min-h-[44px] flex-1 rounded-md text-sm font-medium transition-colors",
              tab === key ? "bg-ink text-paper" : "text-ink-soft hover:text-ink",
            )}
          >
            {label}
          </button>
        ))}
      </div>

      {/* Mobile stacked view */}
      <div className="mt-3 space-y-4 lg:hidden">
        {tab === "timeline" && timelinePane}
        {tab !== "timeline" && (
          <div className="space-y-4">
            {tab === "hypotheses" ? (
              <section className="rounded-xl border border-line bg-card p-4">
                <HypothesisPanel hypotheses={snapshot.hypotheses} />
              </section>
            ) : (
              rightColumn
            )}
          </div>
        )}
      </div>

      {/* Desktop split view */}
      <div className="mt-4 hidden gap-4 lg:grid lg:grid-cols-[1.4fr_1fr]">
        {timelinePane}
        <div className="space-y-4">{rightColumn}</div>
      </div>
    </div>
  );
}
